﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Migrator.Entities;
using Migrator.Services.DHCP.Packets;
using Migrator.Util;
using Migrator.Packets;

namespace Migrator.Services.DHCP
{
    /// <summary>
    /// Simple DHCP client
    /// </summary>
    public class DHCPClient : IService
    {
        public DHCPClient(Node client)
        {
            this.Client = client;
        }

        public void Update()
        {
            if (this.Client.IPAddress == IPAddress.NullAddress && timeSinceLastDiscover > 10)
            {
                Discover();
            }
            else
            {
                timeSinceLastDiscover++;
            }
        }

        public bool Filter(IPPacket packet)
        {
            // DHCP client is only interested in DHCP offer's and DHCP ack's
            return (packet is DHCPOfferPacket || packet is DHCPAckPacket);
        }

        public void Handle(IPPacket packet)
        {
            if (packet is DHCPOfferPacket)
                this.Handle((DHCPOfferPacket)packet);

            else if (packet is DHCPAckPacket)
                this.Handle((DHCPAckPacket)packet);
        }

        public IService Configure(params object[] configuration)
        {
            this.Enabled = true;
            return this;
        }

        public bool Enabled
        {
            get;
            set;
        }

        public Node Client
        {
            get;
            protected set;
        }

        #region Internal methods

        protected void Discover()
        {
            this.Client.Send(new DHCPDiscoverPacket(this.Client));
            timeSinceLastDiscover = 0;
        }

        private void Handle(DHCPOfferPacket packet)
        {
            // Accept the offer if the node needs an IP address
            if (this.Client.IPAddress == IPAddress.NullAddress && !waitingForACK)
            {
                this.Client.Send(new DHCPRequestPacket(this.Client, packet.OfferedIP, packet.SourceIP));
                this.waitingForACK = true;
            }
        }

        private void Handle(DHCPAckPacket packet)
        {
            this.Client.IPAddress = packet.OfferedIP;
            this.Client.DefaultRouter = (Router)packet.Source;
            this.waitingForACK = false;
        }

        #endregion

        private int timeSinceLastDiscover = 1000;
        private bool waitingForACK = false;
    }
}
